#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libdwarf.h>
#include <dwarf.h>

// 解析DW_OP_addr地址信息
void parse_dwarf_addr_info(const char* filename) {
    Dwarf_Debug dbg = 0;
    int res;
    Dwarf_Error error;
    
    printf("=== DW_OP_addr地址信息解析 ===\n");
    printf("文件: %s\n\n", filename);
    
    // 打开DWARF调试信息
    res = dwarf_init_path(filename, &dbg, 0, 0, 0, &error);
    if (res != DW_DLV_OK) {
        printf("无法打开DWARF调试信息\n");
        return;
    }
    
    Dwarf_Unsigned cu_header_length;
    Dwarf_Half version_stamp;
    Dwarf_Unsigned abbrev_offset;
    Dwarf_Half address_size;
    Dwarf_Unsigned next_cu_header;
    Dwarf_Die cu_die;
    
    // 遍历所有编译单元
    while (dwarf_next_cu_header_d(dbg, 1, &cu_header_length, &version_stamp, 
                                 &abbrev_offset, &address_size, &next_cu_header, &error) == DW_DLV_OK) {
        
        if (dwarf_siblingof_b(dbg, NULL, 1, &cu_die, &error) != DW_DLV_OK) {
            continue;
        }
        
        printf("编译单元版本: %d, 地址大小: %d bytes\n", version_stamp, address_size);
        
        // 递归遍历DIE树查找变量
        Dwarf_Die child_die;
        if (dwarf_child(cu_die, &child_die, &error) == DW_DLV_OK) {
            traverse_die_for_addr(dbg, child_die, address_size);
            dwarf_dealloc(dbg, child_die, DW_DLA_DIE);
        }
        
        dwarf_dealloc(dbg, cu_die, DW_DLA_DIE);
    }
    
    dwarf_finish(dbg, &error);
}

// 递归遍历DIE树查找变量地址信息
void traverse_die_for_addr(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Half address_size) {
    Dwarf_Error error;
    Dwarf_Die child_die;
    Dwarf_Half tag;
    
    if (dwarf_tag(die, &tag, &error) != DW_DLV_OK) {
        return;
    }
    
    // 检查是否是变量
    if (tag == DW_TAG_variable) {
        char* name;
        if (dwarf_diename(die, &name, &error) == DW_DLV_OK) {
            // 获取位置信息
            Dwarf_Attribute loc_attr;
            if (dwarf_attr(die, DW_AT_location, &loc_attr, &error) == DW_DLV_OK) {
                Dwarf_Block* block;
                if (dwarf_formblock(loc_attr, &block, &error) == DW_DLV_OK) {
                    // 检查是否是DW_OP_addr操作码
                    if (block->bl_len >= 1 + address_size && block->bl_data[0] == DW_OP_addr) {
                        // 提取地址
                        Dwarf_Addr addr = 0;
                        memcpy(&addr, block->bl_data + 1, address_size);
                        
                        printf("变量: %s\n", name);
                        printf("  DW_OP_addr地址: 0x%016lx\n", addr);
                        printf("  操作码: 0x%02x (DW_OP_addr)\n", DW_OP_addr);
                        printf("  位置信息块大小: %d bytes\n", block->bl_len);
                        printf("  完整位置信息: ");
                        for (int i = 0; i < block->bl_len; i++) {
                            printf("%02x ", block->bl_data[i]);
                        }
                        printf("\n\n");
                    }
                    
                    dwarf_dealloc(dbg, block, DW_DLA_BLOCK);
                }
                dwarf_dealloc(dbg, loc_attr, DW_DLA_ATTR);
            }
            dwarf_dealloc(dbg, name, DW_DLA_STRING);
        }
    }
    
    // 递归遍历子DIE
    if (dwarf_child(die, &child_die, &error) == DW_DLV_OK) {
        traverse_die_for_addr(dbg, child_die, address_size);
        dwarf_dealloc(dbg, child_die, DW_DLA_DIE);
    }
    
    // 遍历兄弟DIE
    Dwarf_Die sibling_die;
    if (dwarf_siblingof_b(dbg, die, 1, &sibling_die, &error) == DW_DLV_OK) {
        traverse_die_for_addr(dbg, sibling_die, address_size);
        dwarf_dealloc(dbg, sibling_die, DW_DLA_DIE);
    }
}

int main(int argc, char* argv[]) {
    if (argc != 2) {
        printf("用法: %s <可执行文件>\n", argv[0]);
        return 1;
    }
    
    parse_dwarf_addr_info(argv[1]);
    return 0;
}